Цель - выявить основной и дополнительный ассортимент интернет-магазина товаров для дома «Пока все ещё тут»
Основные товары это те, которые входят в группу АА, АВ и ВА по выручке и проданному количеству, а дополнительные товары в остальные категории, кроме категории СС.
Описание данных:
Датасет описывает транзакции интернет-магазина товаров для дома и быта «Пока все ещё тут».
Колонки в ecommerce_dataset.csv :
date — дата заказа;customer_id — идентификатор покупателя;order_id — идентификатор заказа;product — наименование товара;quantity — количество товара в заказе;price — цена товара.# импорт библиотек
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.pyplot import figure
import re
import seaborn as sns
from plotly import graph_objects as go
from scipy import stats as st
# импортируем функции для работы со временем
from datetime import datetime, timedelta
# уставнавливаем параметры отображения таблиц
pd.set_option('display.max_colwidth', None)
pd.options.display.float_format ='{:,.3f}'.format
# загружаем датасет
google_id = "1DkqEQWZoHh22YrsYcNUxSzlhgFqdl0tf"
df = pd.read_csv(f"https://drive.google.com/uc?export=download&id={google_id}" )
# выводим первые 5 строк датасета
df.head()
| date | customer_id | order_id | product | quantity | price | |
|---|---|---|---|---|---|---|
| 0 | 2018100100 | ee47d746-6d2f-4d3c-9622-c31412542920 | 68477 | Комнатное растение в горшке Алое Вера, d12, h30 | 1 | 142.000 |
| 1 | 2018100100 | ee47d746-6d2f-4d3c-9622-c31412542920 | 68477 | Комнатное растение в горшке Кофе Арабика, d12, h25 | 1 | 194.000 |
| 2 | 2018100100 | ee47d746-6d2f-4d3c-9622-c31412542920 | 68477 | Радермахера d-12 см h-20 см | 1 | 112.000 |
| 3 | 2018100100 | ee47d746-6d2f-4d3c-9622-c31412542920 | 68477 | Хризолидокарпус Лутесценс d-9 см | 1 | 179.000 |
| 4 | 2018100100 | ee47d746-6d2f-4d3c-9622-c31412542920 | 68477 | Циперус Зумула d-12 см h-25 см | 1 | 112.000 |
# выводим информацию о датасете
df.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 7474 entries, 0 to 7473 Data columns (total 6 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 date 7474 non-null int64 1 customer_id 7474 non-null object 2 order_id 7474 non-null int64 3 product 7474 non-null object 4 quantity 7474 non-null int64 5 price 7474 non-null float64 dtypes: float64(1), int64(3), object(2) memory usage: 350.5+ KB
В таблице 'df' 6 столбцов, 7 474 строки. В каждой строке информация об одном товаре в заказе пользователя. Типы данных float64(1), int64(3), object(2).
Вывод после обзора данных:
Предварительно можно утверждать, что данных достаточно для анализа.
# проверяем дубликаты и пропуски в таблице df
print('Количество дубликатов в таблице df - ',df.duplicated().sum())
print('Количество пропусков в таблице df')
print(df.isna().sum())
Количество дубликатов в таблице df - 0 Количество пропусков в таблице df date 0 customer_id 0 order_id 0 product 0 quantity 0 price 0 dtype: int64
Полных дубликатов и пропусков нет.
# приводим столбец с датой в формат datetime
df['date']= pd.to_datetime(df['date'], format='%Y%m%d%H')
# выводим минимальное и максимальное значения в столбце date в таблице visitors
print('Минимальное значения в столбце date в датасете - ',df['date'].min())
print('Максимальное значения в столбце date в датасете - ',df['date'].max())
Минимальное значения в столбце date в датасете - 2018-10-01 00:00:00 Максимальное значения в столбце date в датасете - 2020-01-31 15:00:00
У нас есть данные о заказах сделанных с 1 октября 2018 года по 31 января 2020 года.
# приводим все названия товаров в нижний ригистр
df['product'] = df['product'].str.lower()
# удаляем строки, где совпадают все столбцы, кроме столбцов с датой
key = ['customer_id', 'order_id','product','quantity','price']
df_dedupped2 = df.drop_duplicates(subset=key)
# выводим информацию о потерях
print("Количество строк в исходном датасете - ",df['date'].count())
print("Количество строк после удаления неявных дубликатов - ",df_dedupped2['date'].count())
print('Доля потерь - ',
"{0:.2%}".format((df['date'].count() - df_dedupped2['date'].count()) / df['date'].count()))
# записываем отфильтрованный датасет в основной
df = df_dedupped2
Количество строк в исходном датасете - 7474 Количество строк после удаления неявных дубликатов - 5610 Доля потерь - 24.94%
В датасете были строки, у которых совпадают значения во всех столбцах, кроме даты. Отбросили такие строки, чтобы они не исказили выводы исследования.
# удаляем строки, с заказами у которых один id на несколько покупателей
a_lot_of_customer = df.groupby('order_id', as_index=False).agg({'customer_id': pd.Series.nunique}).query('customer_id > 1')
df_filtered = df[df.order_id.isin(a_lot_of_customer['order_id'].tolist()) == False]
# выводим информацию о потерях
print("Количество строк в исходном датасете - ",df['date'].count())
print("Количество строк после удаления заказов с двумя и более покупателями- ",df_filtered['date'].count())
print('Доля потерь - ',
"{0:.2%}".format((df['date'].count() - df_filtered['date'].count()) / df['date'].count()))
# записываем отфильтрованный датасет в основной
df = df_filtered
Количество строк в исходном датасете - 5610 Количество строк после удаления заказов с двумя и более покупателями- 5544 Доля потерь - 1.18%
В датасете есть заказы, индентификатор которых встречается у двух клиентов одновременно. Такие заказы придется отбросить, поскольку не может быть один заказ у нескольких покупателей.
#выводим диаграмму boxplot по столбцу 'quantity'
figure(figsize=(15, 6), dpi=80)
df.boxplot(column=['quantity'])
plt.title('Диаграмма размаха количества товаров в заказе')
plt.ylabel('Количество')
plt.show()
В столбце с количеством товара есть выбросы до 1000, возможно это оптовые заказы или ошибка при записи данных. Посмотрим на такие заказы подробнее. Для границы возьмем 95 процентиль.
# находим 99 процентиль для количества
quantity_border = np.percentile(df['quantity'], 95)
# выводим таблицу с выбросами по количеству товаров
df.query('quantity > @quantity_border').sort_values(by='quantity', ascending=False)
| date | customer_id | order_id | product | quantity | price | |
|---|---|---|---|---|---|---|
| 5456 | 2019-06-18 15:00:00 | 312e9a3e-5fca-43ff-a6a1-892d2b2d5ba6 | 71743 | вантуз с деревянной ручкой d14 см красный, burstenmann, 0522/0000 | 1000 | 675.000 |
| 5071 | 2019-06-11 07:00:00 | 146cd9bf-a95c-4afb-915b-5f6684b17444 | 71668 | вешалки мягкие для деликатных вещей 3 шт шоколад | 334 | 148.000 |
| 3961 | 2019-05-20 21:00:00 | 5d189e88-d4d6-4eac-ab43-fa65a3c4d106 | 71478 | муляж яблоко 9 см красное | 300 | 51.000 |
| 1158 | 2018-12-10 14:00:00 | a984c5b7-ff7e-4647-b84e-ef0b85a2762d | 69289 | ручка-скоба рс-100 белая *трибатрон*, 1108035 | 200 | 29.000 |
| 568 | 2018-11-01 08:00:00 | aa42dc38-780f-4b50-9a65-83b6fa64e766 | 68815 | муляж яблоко 9 см красное | 170 | 51.000 |
| ... | ... | ... | ... | ... | ... | ... |
| 1466 | 2019-01-10 11:00:00 | 4e7a2cae-1fd5-4710-b2a5-200685fc85aa | 69764 | муляж желудь 2 шт | 7 | 22.000 |
| 6059 | 2019-08-06 11:00:00 | a0ce9b81-dad7-48f6-a28a-bb671c05166f | 72220 | чайная ложка trendy сталь 2 мм 3 шт attribute act033 | 7 | 172.000 |
| 6046 | 2019-08-04 23:00:00 | 5c265590-edb1-4ba7-84e1-48ccf5c9e703 | 14912 | рассада зелени для кухни тимьян вариегэйтид диам. 9 см | 7 | 120.000 |
| 1423 | 2019-01-01 14:00:00 | 0bbff16a-75df-4947-a5ef-f577c031a19d | 69689 | вешалка металлическая valiant с четырьмя разъемными перекладинами противоскользящим покрытием 35*30 см 18b30 | 7 | 135.000 |
| 3791 | 2019-05-14 19:00:00 | bea7a833-2074-42db-bc49-4457abd3c930 | 14776 | пеларгония зональная махровая лососевая | 7 | 161.000 |
258 rows × 6 columns
Есть заказ с 1000 вантузов или 170 муляжей яблок, наверняка это оптовые заказы или ошибка в данных, такие заказы могут повлиять на анализ, отбросим такие заказы.
#выводим диаграмму boxplot по столбцу'price'
figure(figsize=(15, 6), dpi=80)
df.boxplot(column=['price'])
plt.title('Диаграмма размаха стоимости товаров')
plt.ylabel('Стоимость')
plt.show()
В столбце со стоимостью товаров есть выбросы больше 14000, возможно это дорогие товары или ошибка при записи данных. Посмотрим на них подробнее.
# находим 95 процентиль для стоимости
price_border = np.percentile(df['price'], 95)
df.query('price > @price_border').sort_values(by='price', ascending=False)
| date | customer_id | order_id | product | quantity | price | |
|---|---|---|---|---|---|---|
| 5992 | 2019-07-29 17:00:00 | 0d87f4ae-465a-4fac-81e6-5d629761783e | 72139 | сушилка уличная leifheit 85210 linomatic v 400 40 м 175х237х237 см зеленая | 1 | 14,917.000 |
| 2697 | 2019-04-05 19:00:00 | c0c60544-3a99-49d0-8a8e-cf7f293c22cb | 71035 | сумка-тележка хозяйственная andersen royal shopper, hera, синяя 166-004-90 | 1 | 8,737.000 |
| 1981 | 2019-02-24 10:00:00 | ac250053-a236-467a-97d2-ddbb9bf4a1ba | 70423 | сумка-тележка хозяйственная andersen alu star shopper, hava, синяя 115-103-90 | 1 | 8,437.000 |
| 7436 | 2020-01-26 19:00:00 | 04416514-5346-4f90-93e3-fb7365e2ee8c | 109758 | сумка-тележка хозяйственная rolser mnb019 rojo logic dos+2 красная | 1 | 8,077.000 |
| 2997 | 2019-04-21 16:00:00 | 19d904d8-8d16-476d-8f66-b2a3b7a23660 | 71227 | сумка-тележка хозяйственная rolser mnb019 rojo logic dos+2 красная | 1 | 8,077.000 |
| ... | ... | ... | ... | ... | ... | ... |
| 5721 | 2019-07-08 06:00:00 | 99380b8a-8be1-41e5-9c61-fc80cce43de5 | 71901 | гладильная доска ника blues 124х46 см 5757 | 1 | 2,527.000 |
| 5657 | 2019-07-04 19:00:00 | 5c61842f-c056-477b-acee-58a6115647b8 | 71874 | гладильная доска ника blues 124х46 см 5757 | 1 | 2,527.000 |
| 4908 | 2019-06-09 00:00:00 | 2cbff118-d80c-4080-b4d0-acca972e5cf6 | 71647 | гладильная доска ника blues 124х46 см 5757 | 1 | 2,527.000 |
| 6636 | 2019-10-16 20:00:00 | 07e68a7f-22ed-4c8a-b0d1-79ba886a1be0 | 72999 | сушилка для белья напольная colombo double алюминий st797 | 1 | 2,474.000 |
| 6643 | 2019-10-17 13:00:00 | 73d1cd35-5e5f-4629-8cf2-3fda829d4e58 | 73008 | сушилка для белья gimi dinamik 20 | 1 | 2,474.000 |
269 rows × 6 columns
Самый дорогой товар это "сушилка уличная leifheit", это нормальная стоимость для такого рода товаров. Цены остальных товаров тоже примерно соответствуют. Можно предпотоложить, что среди цен нет аномальных значений.
# отбрасываем заказы со значениями выше 95 процентиля
df_filtered = df.query('quantity < @quantity_border')
# выводим информацию о потерях
print("Количество строк в исходном датасете - ",df['date'].count())
print("Количество строк после удаления аномального количества товаров- ",df_filtered['date'].count())
print('Доля потерь - ',
"{0:.2%}".format((df['date'].count() - df_filtered['date'].count()) / df['date'].count()))
# записываем отфильтрованный датасет в основной
df = df_filtered
Количество строк в исходном датасете - 5544 Количество строк после удаления аномального количества товаров- 5244 Доля потерь - 5.41%
Отбросили заказы с количеством товара больше 95-го процентиля.
# создаем функцию для распределения товаров по категориям
def category(name):
# если есть значение d- в названии товара, то присваеваем категорию "Растения и цветы"
if name.find('d-') > 0 and name.find('см') > 0:
return "Растения и цветы"
# создаем словарь категорий и товаров, которые в нее входят
category = {'Предметы для хранения и переноски': ['сушилка', 'таз', 'чехол', 'корзина', 'сумка-тележка', 'сумка',
'контейнер', 'кувшин', 'вешалка-плечики', 'корыто', 'банка', 'вешалка',
'вешалка-стойка', 'лоток', 'вешалка-сушилка', 'этажерка', 'коробка',
'ведро', 'емкость', 'полка', 'обувница-3', 'ящик', 'корзинка', 'ваза',
'стеллаж', 'вешалки', 'вешалка-плечики', 'полки', 'комод',
'урна-пепельница', 'плечики', 'пакет','мешок', 'кофр','подставка',
'тележка','короб', 'наматрицник-чехол','бак'],
'Предметы для кухни': ['тарелка','котел','толкушка','скатерть','противень','вкладыши','миксер','чайник',
'термокружка','светильник','доска-стремянка','сковорода','овощеварка',
'картофелемялка','рассекатель','мантоварка','подрукавник','мантоварка-пароварка',
'салатник','кастрюля','насадка-отжим','форма','орехоколка','насадка','сито',' тортница',
'блюдо','насадка-моп','сотейник','кипятильник',
'решетка','щетка','ложка','нож','термостакан','электроштопор','термос','просеиватель',
'соль','скалка','соковыжималка','миска','хлебница','форма','бидон','рыбочистка',
'овощечистка','рукав','венчик','ножеточка','ковш','скалка', 'сахарница', 'стакан',
'соковарка', 'шприц', 'крышка', 'терка', 'отделитель', 'тортница', 'блюдце', 'экран',
'пресс', 'весы', 'вилка', 'измельчитель','кружка', 'салфетка','tepмокружка', 'масленка',
'лопатка','кисточка','ножницы','мини-сковорода'],
'Предметы для уборки': ['перчатки','мыло','щетка','паста','ёрш','мыльница',' швабра','вантуз',' средство',
'пылесос','мыло-скраб','маска','мыло','утюг','скребок','тряпкодержатель',' тряпка',
'концентрат','дозатор','кондиционер','гель','совок','щётка', 'тряпка', 'отжим',
'средство','швабра', 'щетка-сметка', 'ополаскиватель', 'сетка','биопорошок','пена',
'ерш', 'бальзам','ролик', 'блок','антижир','губка','окномойка','веник',],
'Предметы для дома': ['муляж','ковер','штора','комплект','карниз','штора','коврик','фоторамка','халат',
'подголовник','полотенце','простыня','белье','подушка','наматрасник','салфетки',
'покрывало',' подкладка','набор','пододеяльник','наматрасник','ковер','простынь',
'простыня','плед','ковёр','салфетница', 'ванна','пуф', 'наволочка', 'кашпо', 'штанга',
'композиция', 'одеяло', 'сиденье'],
'Различные предметы': ['доска','лестница-стремянка','термометр','ключница','кольца','шнур','петля',
'крючок',' штанга','решетка','штангенциркуль','ручка-скоба','бензин','стремянка',
'инструмент','стремянка-табурет','петля-стрела','шпагат','основание', 'стяжки',
'линейка,', 'пьезозажигалка', 'ручка', 'ткань', 'веревка', 'покрытие', 'угольник,',
'стяжка','лист', 'сверло','прищепки', 'стремянки', 'лиана', 'лестница', 'шило',
'подкладка','крем','сверло-фреза,','фен','держатель', 'пробка','табак','сварка','урна'],
'Растения и цветы': ['гипсофила','хризантема','калла','дендробиум','гортензия','газания','целозия','вероника',
'антинакипин','петуния','змееголовник','физостегия','базилик','калибрахоа','пуансеттия',
'платикодон','гвоздика','примула','незабудка','кореопсис','лантана','вербейник','фуксия',
'декабрист','овсянница','астра','томат','виола','календула','цикламен','энотера',
'бархатцы','укроп','цинния','ранункулус','пиретрум','котовник','вербена','цинерания',
'тагетис','растение','герань','рассада','гиностемма','роза','бульонница','пеларгония',
'кодонанта','цикламен','антуриум','фал','вероника', 'огурец', 'тюльпан', 'зев', 'настурция',
'петрушка', 'бакопа', 'тимьян','космея', 'кипарисовик', 'клубника', 'флокс', 'бегония',
'портулак', 'клен', 'томата','цикламен,', 'дерево', 'цветок','алиссум','годеция','капуста',
'лапчатка','цинерария', 'эшшольция','ель','аквилегия','горох','земляника','седум',
'георгина', 'смолевка','лавр','колокольчик','эхинацея','ясколка','лилейник', 'папоротник',
'дыня','бальзамин','лобелия','виноград','агератум','колеус', 'аргирантерум','маттиола',
'сальвия','лук','арбуз','хоста','гайлардия', 'монарда','нивянник','рудбекия','барвинок',
'осина','бузульник', 'камнеломка', 'солидаго', 'бадан', 'лен', 'лаватера', 'анемона',
'буддлея', 'валериана', 'любисток', 'сельдерей', 'шалфей', 'вигна', 'салат','кориандр',
'морковь','афеляндра'],
}
# разделяем название на отдельные слова
n = re.split(' ', name)
# собираем шаблон для поиска прилагательных
adjective = ['ый$','ий$','ой$','ая$','яя$','ое$','ее$','ые$']
chk_pat = '(?:{})'.format('|'.join(adjective))
# создаем пары ключ-товары
category_items = category.items()
# проходим по каждому слову из названия
for w in n:
# если это не прилагательное, то ищем это слово в словаре категорий
if not bool(re.search(chk_pat, w, flags=re.I)):
for key, value in category_items:
if w in value:
return(key)
# если не нашли, то присваеваем это слово как категорию
return w
# добавляем категорию для каждого товара
df['category'] = df['product'].apply(category)
# выведем уникальные значения категорий
print(df['category'].value_counts())
Растения и цветы 2800 Предметы для хранения и переноски 1115 Предметы для дома 515 Предметы для кухни 392 Различные предметы 295 Предметы для уборки 127 Name: category, dtype: int64
Отлично, категории присвоились всем товарам.
Вывод после предобработки
В ходе предобработки мы исследовали дубликаты и пропуски, соответствие типов данных и значений столбцов, аномальные значения, выделили товарные категории.
Полных дубликатов и пропусков не обнаружили. Удалили неявные дубликаты, то есть заказы у которых совпадали все столбцы, кроме даты. Привели столбец с датой в тип datetime. Удалили заказы, у которых было несколько покупателей. Удалили аномальные значения количества товаров. Выделили 6 товарных категорий и распределили товары по этим категориям.
Данные готовы к анализу.
# создаем столбец с округленной до месяца датой
df['month'] = df['date'].dt.to_period('M').dt.to_timestamp()
# создаем столбец с номером месяца
df['year'] = df['date'].dt.year
# создаем столбец с номером месяца
df['month_num'] = df['date'].dt.month
# создаем столбец с номером месяца
df['week'] = df['date'].dt.isocalendar().week
# создаем столбец с номером месяца
df['day'] = df['date'].dt.day
# создаем столбец с номером дня недели
df['weekday'] = df['date'].dt.weekday
# создаем столбец с часом совершения заказа
df['hour'] = pd.DatetimeIndex(df['date']).hour
# выводим общие продажи и количество проданных товаров по категориям
sales_per_category = (df.groupby('category', as_index=False)
.agg({'price':'sum','quantity':'sum'})
.sort_values(by='price', ascending=False))
sales_per_category
| category | price | quantity | |
|---|---|---|---|
| 3 | Предметы для хранения и переноски | 1,401,274.583 | 1285 |
| 4 | Различные предметы | 423,560.833 | 349 |
| 5 | Растения и цветы | 413,650.833 | 3579 |
| 0 | Предметы для дома | 375,998.833 | 688 |
| 1 | Предметы для кухни | 225,554.500 | 532 |
| 2 | Предметы для уборки | 60,804.500 | 165 |
Построим графики для наглядности.
# устанавливаем размер графика
sns.set(rc={'figure.figsize':(10,5)})
# выводим график выручки по категориям
ax = sns.barplot(data=sales_per_category, x="price", y='category')
ax.set_title('Выручка по категориям')
ax.set(xlabel='Выручка', ylabel='Категория')
plt.show()
Больше всего выручки принесли товары из категории "Предметы для хранения и переноски", меньше всего "Предметы для уборки"
# устанавливаем размер графика
sns.set(rc={'figure.figsize':(10,5)})
# выводим график количества проданых товаров по категориям
ax = sns.barplot(data=sales_per_category.sort_values(by='quantity', ascending=False), x="quantity", y='category')
ax.set_title('Продажи товаров по категориям')
ax.set(xlabel='Количество проданных товаров', ylabel='Категория')
plt.show()
По количеству проданных товаров лидирует "Растения и цветы", но по выручке они на втором месте. Их продается много, но они не такие дорогие, как "Предметы для хранения и переноски", которые лидирут по выручке.
Категория "Различные предметы" по количеству продается меньше, чем категория "Растения и цветы", но выручки генерирует одинаково с ней.
Предметы для уборки и по выручке и по количеству на последнем месте.
# выводим график выручки категории по месяцам
month_revenue_per_category = df.pivot_table(index='month', columns='category', values='price', aggfunc='sum')
month_revenue_per_category.plot(grid=True,figsize=[20,10])
plt.title("График выручки категорий по месяцам")
plt.xlabel("Месяц")
plt.ylabel("Выручка")
plt.show()
На графике видно, как растет выручка у категории "Растения и цветы" в апреле-мае, возможно это связано с подготовкой к дачному сезону.
Выручка категории "Предметы для хранения и переноски" имеет достигает своего пика в октябре 2018, но также имеет локальные пики в декабре, феврале, июле. Провалы в выручке наблюдаются в январе, ноябре, мае и июне.
Остальные категории держатся более стабильно на протяжении года.
# выводим график количества проданых товаров категории по месяцам
month_quantity_per_category = df.pivot_table(index='month', columns='category', values='quantity', aggfunc='sum')
month_quantity_per_category.plot(grid=True,figsize=[20,10])
plt.title("График количества проданых товаров категорий по месяцам")
plt.xlabel("Месяц")
plt.ylabel("Количество проданных товаров")
plt.show()
На графике видно, как начиная с февраля резко растет количество проданных растений и достигает своего пика в мае, после чего снижается. Можно предположить что в апреле-мае начинается подготовка к дачному сезону и продажи растений растут.
Остальные категории ведут себя относительно стабильно на протяжении всего года по сревнению с растениями.
Выводы:
Больше всего выручки приносят товары из категории "Предметы для хранения и переноски".
По количеству проданных товаров лидирует "Растения и цветы", но по выручке они на втором месте. Можно сделать вывод, что их продается много, но они не такие дорогие, как "Предметы для хранения и переноски", которые лидирут по выручке.
В мае выручка и количество проданных товаров категории "Растения и цветы" достигает пика и сильно выше всех остальных категорий, возможно это связано с подготовкой к дачному сезону.
Выручка категории "Предметы для хранения и переноски" имеет достигает своего пика в августе, но также имеет локальные пики в феврале, октябре и декабре.
Категория "Различные предметы" по количеству продается меньше по количеству, чем категория "Предметы для кухни", но выручки генерирует одинаково с ней.
Предметы для уборки и по выручке и по количеству на последнем месте.
Остальные категории держатся стабильно на протяжении года.
# выводим таблицу с выручкой и количеством проданных товаров по году и месяцу
sales_per_month = df.groupby('month',as_index=False).agg({'price':'sum','quantity':'sum'})
sales_per_month
| month | price | quantity | |
|---|---|---|---|
| 0 | 2018-10-01 | 264,140.000 | 561 |
| 1 | 2018-11-01 | 227,686.000 | 483 |
| 2 | 2018-12-01 | 254,050.000 | 367 |
| 3 | 2019-01-01 | 121,257.000 | 199 |
| 4 | 2019-02-01 | 223,187.000 | 419 |
| 5 | 2019-03-01 | 198,634.000 | 461 |
| 6 | 2019-04-01 | 213,880.000 | 873 |
| 7 | 2019-05-01 | 167,441.000 | 940 |
| 8 | 2019-06-01 | 125,529.000 | 389 |
| 9 | 2019-07-01 | 182,848.000 | 362 |
| 10 | 2019-08-01 | 151,811.000 | 251 |
| 11 | 2019-09-01 | 139,622.000 | 246 |
| 12 | 2019-10-01 | 166,312.000 | 245 |
| 13 | 2019-11-01 | 119,393.417 | 236 |
| 14 | 2019-12-01 | 181,495.333 | 265 |
| 15 | 2020-01-01 | 163,558.333 | 301 |
Построим график для наглядности.
# устанавливаем размеры графика
plt.figure(figsize=(20,5))
# выводим график выручки по году и месяцу
plt.plot(sales_per_month['month'], sales_per_month['price'])
plt.title("График выручки по месяцам")
plt.xlabel("Месяц")
plt.ylabel("Выручка")
plt.show()
Выручка постепенно снижается. Самая высокая выручка была в октябре 2018 года около 185 000, а в октябре 2019 года уже около 92 000.
#выведем таблицу со средней выручкой и количеством проданных товаров по месяцам
mean_sales_per_month = (df.groupby(['year','month_num'], as_index=False)
.agg({'price':'sum','quantity':'sum','order_id':pd.Series.nunique})
.groupby('month_num')
.agg({'price':'mean','quantity':'mean','order_id':'mean'}))
mean_sales_per_month
| price | quantity | order_id | |
|---|---|---|---|
| month_num | |||
| 1 | 142,407.667 | 250.000 | 206 |
| 2 | 223,187.000 | 419.000 | 258 |
| 3 | 198,634.000 | 461.000 | 216 |
| 4 | 213,880.000 | 873.000 | 235 |
| 5 | 167,441.000 | 940.000 | 166 |
| 6 | 125,529.000 | 389.000 | 145 |
| 7 | 182,848.000 | 362.000 | 182 |
| 8 | 151,811.000 | 251.000 | 164 |
| 9 | 139,622.000 | 246.000 | 169 |
| 10 | 215,226.000 | 403.000 | 199 |
| 11 | 173,539.708 | 359.500 | 202 |
| 12 | 217,772.667 | 316.000 | 253 |
Построим графики для наглядности.
# устанавливаем размер графика
sns.set(rc={'figure.figsize':(15,5)})
# выводим график со средним количеством заказов по месяцам
ax = sns.barplot(data=mean_sales_per_month, y="order_id", x=mean_sales_per_month.index)
ax.set_title('Среднее количество заказов по месяцам')
ax.set(xlabel='Номер месяца', ylabel='Среднее количество заказов')
plt.show()
Больше всего заказов в феврале и декабре и апреле. Меньше всего в июне, июле и мае.
# устанавливаем размер графика
sns.set(rc={'figure.figsize':(15,5)})
# выводим график со средней выручкой по месяцам
ax = sns.barplot(data=mean_sales_per_month, y="price", x=mean_sales_per_month.index)
ax.set_title('Средняя выручка по месяцам')
ax.set(xlabel='Номер месяца', ylabel='Средняя выручка')
plt.show()
Самая большая выручка в октябре, январе и апреле. Меньше всего в июне, августе и январе.
# устанавливаем размер графика
sns.set(rc={'figure.figsize':(15,5)})
# выводим график со средним количеством товаров по месяцам
ax = sns.barplot(data=mean_sales_per_month, y="quantity", x=mean_sales_per_month.index)
ax.set_title('Среднее количество проданных товаров по месяцам')
ax.set(xlabel='Номер месяца', ylabel='Среднее количество проданных товаров')
plt.show()
Больше всего проданных товаров в апреле и мае. Меньше всего проданных товаров в августе, январе и сентябре.
Выводы:
Больше всего заказов в феврале и декабре и апреле. Меньше всего в июне, июле и мае.
Самая большая выручка в октябре, январе и апреле. При этом количество заказов и проданных товаров в октябре не самое высокое, можно предположить, что это связано с высокими продажами в октябре 2018 года. Меньше всего выручка в июне, августе и январе.
Больше всего проданных товаров в апреле и мае, как мы уже выяснили, это связано с пиком спроса на растения и цветы. Меньше всего проданных товаров в августе, январе и сентябре.
#выведем таблицу со средней выручкой и количеством проданных товаров по дням недели
sales_per_weekday = (df.groupby(['week','weekday'], as_index=False)
.agg({'price':'sum','quantity':'sum','order_id':pd.Series.nunique})
.groupby('weekday')
.agg({'price':'mean','quantity':'mean','order_id':'mean'}))
sales_per_weekday
| price | quantity | order_id | |
|---|---|---|---|
| weekday | |||
| 0 | 9,051.968 | 23.077 | 10.269 |
| 1 | 8,977.683 | 19.596 | 10.404 |
| 2 | 8,878.965 | 18.558 | 9.673 |
| 3 | 8,601.487 | 20.962 | 9.692 |
| 4 | 7,845.418 | 16.827 | 8.192 |
| 5 | 5,674.370 | 12.820 | 6.660 |
| 6 | 7,110.559 | 15.843 | 8.294 |
Построим графики для наглядности.
# устанавливаем размер графика
sns.set(rc={'figure.figsize':(15,5)})
# выводим график со среднего количества заказов по дням недели
ax = sns.barplot(data=sales_per_weekday, y="order_id", x=sales_per_weekday.index)
ax.set_title('Среднее количество заказов по дням недели')
ax.set(xlabel='Номер дня недели', ylabel='Среднее количество заказов')
plt.show()
# устанавливаем размер графика
sns.set(rc={'figure.figsize':(15,5)})
# выводим график со средней выручкой по дням недели
ax = sns.barplot(data=sales_per_weekday, y="price", x=sales_per_weekday.index)
ax.set_title('Средняя выручка по дням недели')
ax.set(xlabel='Номер дня недели', ylabel='Средняя выручка')
plt.show()
Больше всего выручка и количество заказов в понедельник и плавно снижается до субботы, а в воскресенье начинает расти.
# устанавливаем размер графика
sns.set(rc={'figure.figsize':(15,5)})
# выводим график со средним количество проданных товаров по дням недели
ax = sns.barplot(data=sales_per_weekday, y="quantity", x=sales_per_weekday.index)
ax.set_title('Среднее количество проданных товаров по дням недели')
ax.set(xlabel='Номер дня недели', ylabel='Среднее количество проданных товаров')
plt.show()
Больше всего количество проданных товаров в понедельник, четверг и вторник. Меньше всего в субботу, воскресенье и пятницу.
Выводы:
Больше всего выручка и количество заказов в понедельник и плавно снижается до субботы, а в воскресенье начинает расти.
Больше всего количество проданных товаров в понедельник, четверг и вторник. Меньше всего в субботу, воскресенье и пятницу.
#выведем таблицу со средней выручкой и количеством проданных товаров по часам
sales_per_hour = (df.groupby(['day','hour'])
.agg({'price':'sum','quantity':'sum','order_id':pd.Series.nunique})
.groupby('hour')
.agg({'price':'mean','quantity':'mean','order_id':'mean'}))
sales_per_hour
| price | quantity | order_id | |
|---|---|---|---|
| hour | |||
| 0 | 1,336.350 | 3.033 | 1.967 |
| 1 | 1,431.118 | 3.706 | 1.824 |
| 2 | 1,645.312 | 1.688 | 1.375 |
| 3 | 1,228.444 | 1.111 | 1.111 |
| 4 | 1,014.564 | 2.154 | 1.308 |
| 5 | 1,222.233 | 2.600 | 1.400 |
| 6 | 1,819.105 | 2.000 | 1.684 |
| 7 | 2,755.393 | 3.750 | 2.393 |
| 8 | 4,407.016 | 9.387 | 4.419 |
| 9 | 5,243.839 | 12.742 | 6.032 |
| 10 | 6,228.973 | 14.645 | 7.774 |
| 11 | 7,700.726 | 16.000 | 8.323 |
| 12 | 7,348.151 | 16.645 | 8.484 |
| 13 | 6,897.753 | 19.194 | 7.806 |
| 14 | 6,690.274 | 15.871 | 7.613 |
| 15 | 5,851.554 | 15.161 | 7.323 |
| 16 | 5,774.155 | 14.793 | 6.517 |
| 17 | 5,892.613 | 13.645 | 5.839 |
| 18 | 5,162.013 | 8.710 | 4.968 |
| 19 | 4,760.032 | 10.484 | 5.161 |
| 20 | 3,994.000 | 8.867 | 4.600 |
| 21 | 4,538.602 | 10.000 | 5.129 |
| 22 | 3,598.011 | 9.710 | 4.258 |
| 23 | 2,228.621 | 5.655 | 3.655 |
Построим графики для наглядности.
# устанавливаем размер графика
sns.set(rc={'figure.figsize':(15,5)})
# выводим график со средним количеством заказов по часам
ax = sns.barplot(data=sales_per_hour, y="order_id", x=sales_per_hour.index)
ax.set_title('Среднее количество заказов по часам')
ax.set(xlabel='Час', ylabel='Среднее количество заказов')
plt.show()
Количество заказов плавно растет с 4 утра и достигает пика в 12 часов, далее постепенно снижается до 3 утра.
# устанавливаем размер графика
sns.set(rc={'figure.figsize':(15,5)})
# выводим график со средней выручкой по часам
ax = sns.barplot(data=sales_per_hour, y="price", x=sales_per_hour.index)
ax.set_title('Средняя выручка по часам')
ax.set(xlabel='Час', ylabel='Средняя выручка')
plt.show()
Выручка плавно растет в течении дня с 5 утра и достигает пика в 11 часов дня, далее плавно снижается до 4 утра.
# устанавливаем размер графика
sns.set(rc={'figure.figsize':(15,5)})
ax = sns.barplot(data=sales_per_hour, y="quantity", x=sales_per_hour.index)
ax.set_title('Среднее количество проданных товаров по месяцам')
ax.set(xlabel='Номер месяца', ylabel='Среднее количество проданных товаров')
plt.show()
Больше всего товаров заказывают в 13 часов, меньше всего в 3 часа ночи.
Вывод:
Основные заказы приходят с 8 утра до 11 вечера. Пик заказов приходится на 12 часов, выручки на 11 часов, количества товаров на 13 часов. Меньше всего заказов и количества товаров в 3 утра. А выручки меньше всего в 4 часа утра.
df.groupby('order_id').agg({'price':'sum'}).hist(bins=30)
array([[<AxesSubplot:title={'center':'price'}>]], dtype=object)
Мы проанализировали продажи интернет-магазина товаров для дома и быта «Пока все ещё тут» по категориям, месяцам, дням недели и часам.
Исходя из проведенного исследования, можно сделать следующие общие выводы по исследованию продаж интернет-магазина:
Эти выводы могут помочь интернет-магазину оптимизировать свою стратегию продаж, учитывая популярность категорий товаров, пики спроса в определенные месяцы и дни недели, а также время, когда осуществляются основные заказы.
Для выделения основного и дополнительного ассортимента проведем АВС анализ по выручке и количеству проданных товаров.
ABC анализ позволяет рассортировать список товаров на три группы, которые оказывают разное влияние на выручку или количество проданных товаров.
После распределения товаров на группы по выручке и по количеству объеденим их группы и у нас получится группы АА, АВ, АС, ВА и так далее. Группу АА будем считать основным ассортиментом, она продается лучше всего. Все остальные группы, кроме СС, будем считать дополнительным ассортиментом. Группу СС, то есть товары которые продаются хуже всего выделим отдельно, возможно это новые товары и они еще не успели набрать достаточно продаж.
# собераем все товары в таблицу с общей суммой продаж и количеством
product = df.groupby(['product','category'], as_index=False).agg({'price':'sum', 'quantity':'sum'})
# выводим количество товаров в таблице
print('Количество товаров - ', product['product'].count())
Количество товаров - 2219
# вычисляем долю товара от общей выручки и количества
product['%_price'] = product['price'] / product['price'].sum()
product['%_quantity'] = product['quantity'] / product['quantity'].sum()
# вычисляем кумулятивную сумму доли выручки и количества
product['cumsum_%_price'] = product.sort_values(by='%_price', ascending=False)['%_price'].cumsum()
product['cumsum_%_quantity'] = product.sort_values(by='%_quantity', ascending=False)['%_quantity'].cumsum()
# создаем функцию для распределения товаров по группам
def group(share):
if share < 0.8:
return "A"
elif share < 0.95:
return "B"
else:
return "C"
# распределяем товары по группам
product['price_group'] = product['cumsum_%_price'].apply(group)
product['quantity_group'] = product['cumsum_%_quantity'].apply(group)
# собираем две группы в одну
product['group'] = product['price_group'] + product['quantity_group']
# присваевам категорию ассортимента
product['assortment'] = product['group'].apply(lambda x: 'Основной' if x in ['AA','AB','BA'] else ('Дополнительный' if x != 'CC' else "Неликвид"))
# выводим основной ассортимент
product.query('assortment == "Основной"')
| product | category | price | quantity | %_price | %_quantity | cumsum_%_price | cumsum_%_quantity | price_group | quantity_group | group | assortment | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | tepмокружка avex freeflow 700 мл зеленый avex0759 | Предметы для кухни | 4,798.000 | 2 | 0.002 | 0.000 | 0.461 | 0.769 | A | A | AA | Основной |
| 2 | tepмокружка avex recharge 500 мл голубой avex0681 | Предметы для кухни | 4,198.000 | 2 | 0.001 | 0.000 | 0.495 | 0.846 | A | B | AB | Основной |
| 3 | автоматическая щетка leifheit для мытья окон с ручкой 43 см. 51114 | Предметы для кухни | 14,458.000 | 2 | 0.005 | 0.000 | 0.135 | 0.848 | A | B | AB | Основной |
| 16 | алоэ вера d-12 см h-25 см | Растения и цветы | 693.500 | 4 | 0.000 | 0.001 | 0.892 | 0.579 | B | A | BA | Основной |
| 23 | антуриум андрианум ванилла d-12 см | Растения и цветы | 1,809.000 | 3 | 0.001 | 0.000 | 0.727 | 0.635 | A | A | AA | Основной |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2191 | эвкалипт гунни d-17 см h-60 см | Растения и цветы | 9,866.000 | 6 | 0.003 | 0.001 | 0.230 | 0.348 | A | A | AA | Основной |
| 2199 | этажерка для обуви ника этп3/з с ящиком золотой | Предметы для хранения и переноски | 3,936.000 | 3 | 0.001 | 0.000 | 0.516 | 0.618 | A | A | AA | Основной |
| 2203 | эхеверия перл фон нюрнберг d-7 см | Растения и цветы | 357.000 | 3 | 0.000 | 0.000 | 0.947 | 0.626 | B | A | BA | Основной |
| 2210 | ящик для хранения textilebox curver 5,7 л 34x20x13 см прозрачный 03003-001-00 | Предметы для хранения и переноски | 448.000 | 4 | 0.000 | 0.001 | 0.929 | 0.583 | B | A | BA | Основной |
| 2213 | ящик почтовый металлический с ушками для навесного замка домик 1205251 | Предметы для хранения и переноски | 516.000 | 4 | 0.000 | 0.001 | 0.915 | 0.573 | B | A | BA | Основной |
842 rows × 12 columns
# выводим количество товаров в основном ассортименте
print('Количество товаров в основном ассортименте - ', product.query('assortment == "Основной"')['product'].count())
Количество товаров в основном ассортименте - 842
В основной ассортименте у нас 842 товар из 2071. Это наиболее важные товары, нужно следить чтобы они всегда были на складе, а также обеспечивать им рекламную поддержку.
sample = product.query('assortment == "Основной"').groupby('category', as_index=False).agg({'product':'count'}).sort_values(by='product', ascending=False)
# строим круговую диаграмму распределения категорий в оснавном ассортименте
fig = go.Figure(data=[go.Pie(labels=sample['category'], values=sample['product'])])
fig.update_layout(title="Распределение категорий в основном ассортименте")
fig.show()
Большая часть товаров в оснавном ассортименте находится в категории "Предметы для хранения и переноски", на втором месте "Растения и цветы"
# выводим долнительный ассортимент
product.query('assortment == "Дополнительный"')
| product | category | price | quantity | %_price | %_quantity | cumsum_%_price | cumsum_%_quantity | price_group | quantity_group | group | assortment | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | tepмокружка avex freeflow 700 мл сталь avex0776 | Предметы для кухни | 2,399.000 | 1 | 0.001 | 0.000 | 0.653 | 0.990 | A | C | AC | Дополнительный |
| 4 | агератум рассада однолетних цветов в кассете по 10 шт | Растения и цветы | 210.000 | 2 | 0.000 | 0.000 | 0.972 | 0.848 | C | B | CB | Дополнительный |
| 5 | адиантум лиза d-12 см | Растения и цветы | 412.000 | 1 | 0.000 | 0.000 | 0.936 | 0.935 | B | B | BB | Дополнительный |
| 6 | азалия индика биколор d-12 см | Растения и цветы | 307.000 | 1 | 0.000 | 0.000 | 0.953 | 0.935 | C | B | CB | Дополнительный |
| 7 | азалия индика биколор d-12 см h-20 | Растения и цветы | 344.000 | 1 | 0.000 | 0.000 | 0.949 | 0.935 | B | B | BB | Дополнительный |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2212 | ящик почтовый металлический с врезным замком почта 1205250 | Предметы для хранения и переноски | 277.000 | 1 | 0.000 | 0.000 | 0.958 | 0.860 | C | B | CB | Дополнительный |
| 2214 | ёрш радиаторный без ручки 1807007 | Предметы для уборки | 120.000 | 3 | 0.000 | 0.000 | 0.988 | 0.632 | C | A | CA | Дополнительный |
| 2215 | ёрш унитазный пластмассовый, ваир 1712002 | Предметы для уборки | 44.000 | 1 | 0.000 | 0.000 | 0.999 | 0.862 | C | B | CB | Дополнительный |
| 2216 | ёрш унитазный с деревянной ручкой , ваир 1712012 | Предметы для уборки | 177.000 | 5 | 0.000 | 0.001 | 0.980 | 0.458 | C | A | CA | Дополнительный |
| 2217 | ёрш унитазный с подставкой wc "люкс", мультипласт, 1712007 | Предметы для уборки | 224.000 | 5 | 0.000 | 0.001 | 0.968 | 0.456 | C | A | CA | Дополнительный |
1170 rows × 12 columns
# выводим количество товаров в долнительном ассортименте
print('Количество товаров в долнительном ассортименте - ', product.query('assortment == "Дополнительный"')['product'].count())
Количество товаров в долнительном ассортименте - 1170
В дополнительном ассортименте у нас 1661 товар, этот товар генерирует меньше выручки, чем оснавной ассортимент, но за ним тоже нужно следить, чтоб были запасы на складе.
sample = product.query('assortment == "Дополнительный"').groupby('category', as_index=False).agg({'product':'count'}).sort_values(by='product', ascending=False)
# строим круговую диаграмму распределения категорий в оснавном ассортименте
fig = go.Figure(data=[go.Pie(labels=sample['category'], values=sample['product'])])
fig.update_layout(title="Распределение категорий в долнительном ассортименте")
fig.show()
Почти половина товаров дополнительного ассортимента находится в категории "Растения и цветы".
# выводим неликвидный ассортимент
product.query('assortment == "Неликвид"')
| product | category | price | quantity | %_price | %_quantity | cumsum_%_price | cumsum_%_quantity | price_group | quantity_group | group | assortment | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 711 | молодило микс d-9 см | Растения и цветы | 112.000 | 1 | 0.000 | 0.000 | 0.992 | 0.951 | C | C | CC | Неликвид |
| 714 | морковь детская сладость 2 г 4660010775921 | Растения и цветы | 10.000 | 1 | 0.000 | 0.000 | 1.000 | 0.951 | C | C | CC | Неликвид |
| 721 | муляж банан, желтый, 21 см, полиуретан, fancy fair/ff xj210 | Предметы для дома | 59.000 | 1 | 0.000 | 0.000 | 0.997 | 0.985 | C | C | CC | Неликвид |
| 723 | муляж виноград 14 см цвет в ассортименте | Предметы для дома | 104.000 | 1 | 0.000 | 0.000 | 0.992 | 0.984 | C | C | CC | Неликвид |
| 724 | муляж виноград 17 см цвет в ассортименте | Предметы для дома | 149.000 | 1 | 0.000 | 0.000 | 0.984 | 0.984 | C | C | CC | Неликвид |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 1488 | стиральный биопорошок bonsai концентрированный для белого белья россия 4607974420573 | Предметы для уборки | 299.000 | 1 | 0.000 | 0.000 | 0.955 | 0.965 | C | C | CC | Неликвид |
| 1489 | столовая ложка 3 шт боннтяжелая слbonn-2 | Предметы для кухни | 299.000 | 1 | 0.000 | 0.000 | 0.955 | 0.964 | C | C | CC | Неликвид |
| 1490 | столовая ложка attribute fortress 2 шт acf622 | Предметы для кухни | 127.000 | 1 | 0.000 | 0.000 | 0.987 | 0.964 | C | C | CC | Неликвид |
| 1521 | суккулент микс d-5 см | Растения и цветы | 74.000 | 1 | 0.000 | 0.000 | 0.996 | 0.968 | C | C | CC | Неликвид |
| 2218 | ёрш унитазный с подставкой wc "стандарт", мультипласт 1712010 | Предметы для уборки | 67.000 | 1 | 0.000 | 0.000 | 0.997 | 1.000 | C | C | CC | Неликвид |
207 rows × 12 columns
# выводим количество товаров в нелеквидном ассортименте
print('Количество товаров в нелеквидном ассортименте - ', product.query('assortment == "Неликвид"')['product'].count())
Количество товаров в нелеквидном ассортименте - 207
207 товаров не попали в основной или дополнительный ассортимент, эти товары генерируют только 5% выручки. Это либо новые или сезонные товары, либо товары аутсайдеры. Если это товары аутсайдеры, то нужно исключить их из ассортимента и замените на новые позиции. Если убрать из ассортимента не получится, то следует поискать все возможные пути для снижения себестоимости.
sample = product.query('assortment == "Неликвид"').groupby('category', as_index=False).agg({'product':'count'}).sort_values(by='product', ascending=False)
# строим круговую диаграмму распределения категорий в оснавном ассортименте
fig = go.Figure(data=[go.Pie(labels=sample['category'], values=sample['product'])])
fig.update_layout(title="Распределение категорий в нелеквидном ассортименте")
fig.show()
По большей части неликвидные товары из категории "Растения и цветы", возможно их положение связано с сезонным спросом на такие товары.
Мы проанализировали ассортимент интернет-магазина товаров для дома и быта «Пока все ещё тут» методом АВС и разделили ассортимент на основной, дополнительный и нелеквидный.
Исходя из проведенного исследования ассортимента интернет-магазина, можно сделать следующие выводы:
Интернет-магазину следует активно управлять своим ассортиментом, обращая внимание на основной и дополнительный ассортимент, а также на товары, которые приносят небольшую выручку или являются неликвидными. Это поможет оптимизировать стратегию продаж и обеспечить удовлетворение потребностей клиентов.
Сформулируем гипотезы.
H_0: Средний чек заказов сделанных в октябре 2018 года = средний чек заказов сделанных в октябре 2019 года
H_a: Средний чек заказов сделанных в октябре 2018 года ≠ средний чек заказов сделанных в октябре 2019 года
alpha = 0.05
results = st.ttest_ind(df.query("month == '2018-10-01'").groupby('order_id').agg({'price':'sum'})['price'],
df.query("month == '2019-10-01'").groupby('order_id').agg({'price':'sum'})['price'],
equal_var=False)
alpha = .05
# вывод значения p-value на экран
print(results.pvalue)
# условный оператор с выводом строки с ответом
if alpha > results.pvalue:
print('Отвергаем нулевую гипотезу')
else:
print('Не получилось отвергнуть нулевую гипотезу')
0.01609521162963455 Отвергаем нулевую гипотезу
Отвергаем нулевую гипотезу, есть статистически значимое различие между средними чеками в октябре 2018 и в октябре 2019 года.
Сформулируем гипотезы.
H_0: Количество товаров заказанных в январе 2019 = количество товаров заказанных в январе 2020 года
H_a: Количество товаров заказанных в январе 2019 ≠ количество товаров заказанных в январе 2020 года
alpha = 0.05
results = st.ttest_ind(df.query("month == '2019-01-01'").groupby('order_id').agg({'quantity':'sum'})['quantity'],
df.query("month == '2020-01-01'").groupby('order_id').agg({'quantity':'sum'})['quantity'],
equal_var=False)
alpha = .05
# вывод значения p-value на экран
print(results.pvalue)
# условный оператор с выводом строки с ответом
if alpha > results.pvalue:
print('Отвергаем нулевую гипотезу')
else:
print('Не получилось отвергнуть нулевую гипотезу')
0.0035314848347383905 Отвергаем нулевую гипотезу
Отвергаем нулевую гипотезу, есть статистически значимое различие между средним количеством товаров заказанных в январе 2019 и в январе 2020 года.
Мы проверили две статистические гипотезы.
О различии средних чеков в октябре 2018 и в октябре 2019 года. - Есть статистически значимое различие между средними чеками в октябре 2018 и в октябре 2019 года
О различии среднего количества товаров заказанных в январе 2019 и в январе 2020 года. - Есть статистически значимое различие между средним количеством товаров заказанных в январе 2019 и в январе 2020 года
1. Мы проанализировали продажи интернет-магазина товаров для дома и быта «Пока все ещё тут» по категориям, месяцам, дням недели и часам.
Исходя из проведенного исследования, можно сделать следующие общие выводы по исследованию продаж интернет-магазина:
2. Мы проанализировали ассортимент интернет-магазина товаров для дома и быта «Пока все ещё тут» методом АВС и разделили ассортимент на основной, дополнительный и нелеквидный.
Исходя из проведенного исследования ассортимента интернет-магазина, можно сделать следующие выводы:
Интернет-магазину следует активно управлять своим ассортиментом, обращая внимание на основной и дополнительный ассортимент, а также на товары, которые приносят небольшую выручку или являются неликвидными. Это поможет оптимизировать стратегию продаж и обеспечить удовлетворение потребностей клиентов.
3. Мы проверили две статистические гипотезы.
О различии средних чеков в октябре 2018 и в октябре 2019 года. - Есть статистически значимое различие между средними чеками в октябре 2018 и в октябре 2019 года
О различии среднего количества товаров заказанных в январе 2019 и в январе 2020 года. - Есть статистически значимое различие между средним количеством товаров заказанных в январе 2019 и в январе 2020 года